<?php
namespace catchAdmin\registration\service;

use app\common\lib\Redis;
use app\common\lib\ZhyxMongo;
use app\common\model\CollectClass as CollectClassModel;
use app\common\model\DiseasePatientTaskDetail;
use app\common\model\FollowHistory as FHModel;
use app\common\model\FollowReport;
use app\common\model\FollowDeliverReport;
use app\common\model\PatientInfo;
use app\common\model\PatientInfo as PatientInfoModel;
use app\common\model\PushMessage;
use app\common\model\PushMessage as PushMessageModel;
use app\common\model\TaskDetail;
use app\common\model\ThreeLevelAssistanceBinding as BindingModel;
use MongoDB\BSON\ObjectId;
use MongoDB\BSON\UtcDateTime;
use app\common\business\Answer;
use app\common\lib\ZhyxBeanstalkd;
use catcher\exceptions\FailedException;
use app\common\model\Follow as FollowModel;
use catchAdmin\permissions\model\Department;
use app\common\model\Project as ProjectModel;
use app\common\model\Followtask as FollowtaskModel;
use catchAdmin\permissions\model\Users as UsersModel;
use think\exception\FileException;

class TaskService
{
    /**
     * 创建随访任务
     * 
     * @param array $param
     * @return array
     */
    public function saveTask(array $param): array
    {
        try{
            $user = request()->user();
            //延迟队列时间
            $delay = strtotime($param['endtime']." 23:59:59") - time();

            if ($delay < 0) {
                throw new FailedException("任务结束时间不能小于当前时间");
            }

            //创建人部门信息
            $department_name = (new Department())->where('id', $user['department_id'])->value('department_name');
            $taskData['creator_department_id'] = $user['department_id'];
            $taskData['creator_department_name'] = $department_name??'';

            //获取患者更多信息
            $patients = (new PatientInfoModel())->getNoSearchData([['id', 'in', $param['id']]], 'id,patientId,sex,name,inage,presentTelphone,inList.diagnose,medicalRecordsNo,bz,inList.inchargeDoctorNo,inList.inchargeDoctorName,inList.inhospitalDeptCode');

            //分配给随访员患者
            //$patientIdArr = array_column($patients,"id");
            $newPatient=[];

            if (intval($param['patient_num']) < count($param['follow_staff'])) {
                throw new FailedException("患者数必须大于随访员数");
            }

            $totalCount = 0;

            //没有$param['follow_staff'][0]['count']则均分患者数
            if (isset($param['follow_staff'][0]['count'])) {
                foreach($param['follow_staff'] as $k => $v){
                    $newPatient[] = $temp =  array_chunk($patients, (int)$v["count"])[0];
                    $patients = array_filter($patients, function($value) use ($temp) {
                        return !in_array($value, $temp);
                    });
                    $totalCount += (int)$v['count'];
                }
            }else{
                foreach($param['follow_staff'] as $k => $v){
                    $count = ceil(intval($param['patient_num']) / count($param['follow_staff']));
                    $newPatient[] = $temp =  array_chunk($patients, $count)[0];
                    $patients = array_filter($patients, function($value) use ($temp) {
                        return !in_array($value, $temp);
                    });
                    $totalCount = intval($param['patient_num']);
                }
            }

            //判断随访方式
            if (isset($param['mode']) && !empty($param['mode'])){
                if ($param['mode'] == 3 || $param['mode'] == '3') {
                    $param['mode'] = 2;
                }else{
                    $param['mode'] = (int)$param['mode'];
                }
            }else{
                $param['mode'] = 0;
            }

            //患者总数不能小于分配数
            if ($param['patient_num'] !== $totalCount) {
                throw new FailedException("分配数与总数不匹配");
            }
            $param['patient_num'] = $totalCount;

            #0 普通创建随访，1 收案群发表单
            if ($param['type'] == 1) {
                $taskData['starttime'] = $param['starttime']??date("Y-m-d");#随访开始日期
            }

            //随访任务参数
            $taskData = [
                'taskname'     => $param['taskname'],#随访任务名
                'patient_num'  => $param['patient_num'],#任务患者数
                'endtime'      => $param['endtime'],#结束时间
                'follow_staff' => $param['follow_staff'],#随访人员(多个)
                'template_id'  => $param['template_id']??'',#问卷模板（多个）
                'sms_id'       => $param['sms_id']??'',#短信模板（多个）
                'status'       => $param['status']??0,#任务状态: 0未开始，1进行中，2已结束
                'mode'         => $param['mode'],#推送方式
                'creator_id'   => $user['id'],#创建人
                'deleted_at'   => $param['deleted_at'],#软删除时间
                'created_y'    => date("Y"),#创建年
                'created_ym'   => date("Y-m"),#创建年月
                'created_ymd'  => new UtcDateTime(time()*1000),//date("Y-m-d"),#创建年月日
                'starttime'    => $param['starttime']??'',//任务开始时间
                'search_request_id' => $param['request_id'] ?? ''
            ];

            //随访患者筛选条件
            if (isset($param['condition'])) {
                $taskData['condition'] = $this->processFilter($param['condition']);
            }

            //保存随访任务
            $task = (new FollowtaskModel());
            $task->addData($taskData);

            //随访的患者（多个）
            $patientDatas = [];
            $followStaffList = [];
            foreach($newPatient as $nk=>$nv) {
                foreach ($nv as $key => $val) {
                    $index = $nk;
                    $patientDatas[] = [
                        'pid' => $val['id'],#患者id
                        'task_id' => new ObjectId($task->id),#随访任务id
                        'taskname' => $param['taskname'],#随访任务名称
                        'patientId' => $val['patientId'],#患者patientId
                        'sex' => $val['sex'],#性别
                        'name' => $val['name'],#姓名
                        'medicalRecordsNo' => $val['medicalRecordsNo'] ?? '',#病案号
                        'mode' => $param['mode'],#方式
                        'inage' => $val['inage'] ?? '',#年龄
                        'status' => 0,#问卷状态
                        'followStatus' => 0,#随访状态
                        'creator_id' => $user['id'],
                        'deleted_at' => $param['deleted_at'],
                        'patient_id' => $val['patientId'],
                        'presentTelphone' => $val['presentTelphone'] ?? '',#电话
                        'diagnosis' => $val['inList']['diagnose'] ?? '',#疾病诊断
                        'follow_staff' => $param['follow_staff'][$index],
                        'create_date' => date("Y-m-d"),
                        'patientDeptId' => $val['inList']['inhospitalDeptCode'] ?? '',
                        'patientdeptName' => $val['inList']['inhospitalDeptCode'] ?? '',
                        'inchargeDoctorNo' => $val['inList']['inhospitalDeptCode'] ?? '',
                        'inchargeDoctorName' => $val['inList']['inhospitalDeptCode'] ?? '',
                        'bz' => $val['bz'] ?? '',#病种
                        'created_at' => time(),
                        'updated_at' => time()
                    ];

                    $staff = $param['follow_staff'][$index];

                    if (!isset($followStaffList[$staff['user_id']])) {
                        $followStaffList[$staff['user_id']] = $staff;
                        $followStaffList[$staff['user_id']]["task_number"] = 1;
                        $followStaffList[$staff['user_id']]["task_id"] = new ObjectId($task->id);
                        $followStaffList[$staff['user_id']]["task_name"] = $param['taskname'];
                        $followStaffList[$staff['user_id']]["created_date"] = new UtcDateTime(time() * 1000);
                        $followStaffList[$staff['user_id']]["task_status"] = $task['status'];
                        $followStaffList[$staff['user_id']]["created_at"] = time();
                        $followStaffList[$staff['user_id']]["updated_at"] = time();
                    } else {
                        $followStaffList[$staff['user_id']]["task_number"] += 1;
                    }
                }
            }

            //保存随访患者
            (new FollowModel())->insertAll($patientDatas);

            //任务汇总表入库
            (new TaskDetail())->insertAll($followStaffList);

            //更新创建患者计划时间节点
            $patientIdArr = array_column($patientDatas, 'pid');
            if(!empty($patientIdArr)) {
                $task_node = [
                    'establish_followtask_node' => [
                        'create_date' => date("Y-m-d"),
                        'taskname' => $param['taskname'],
                        'task_id' => (string)$task->id,
                        'followStatus' => 0,
                        'status' => 0
                    ]
                ];
                (new PatientInfoModel())->whereIn("id", $patientIdArr)->update($task_node);
            }

            //收案创建随访直接推送问卷
            if ($param['type'] == 1)#0 普通创建随访，1 收案群发表单
            {

                $questData = [
                    'projectId'   => $param['template_id'][0]['value']??'',
                    'template_id' => $param['sms_id'][0]['value']??'',
                    'putChanel'   => "sms",
                    'creator_id'  => $user['id'], 
                    'deleted_at'  => $param['deleted_at'],
                    'pushtime'    => $param['pushtime'],
                    'mode'        => $param['mode'],
                    'task_id'     => $task->id,
                    'patientList' => []
                ];
                (new FollowtaskModel())->saveStatus($task->id, ['status' => 1]);
                $follow = (new FollowModel())->getConditionData(['task_id' => new ObjectId($task->id)], 'id');

                foreach ($follow as $key => $val)
                {
                    $questData['patientList'][] = $val['id'];
                }
                $this->pushQuestionnaire($questData);
            }

            //加入更改随访状态队列
            $tubeData['id'] = $task->id;
            $tubeData['data'] = [
                'status' => 2,
                'breaktime' => date("Y-m-d")
            ];
            $tubeData['tubeName'] = 'SendFollowTask';
            ZhyxBeanstalkd::getInstance()->beansTalk->useTube("sendFollowTask")->put(json_encode($tubeData, JSON_THROW_ON_ERROR), 0, $delay);
            return ['id' => $task->id];
        } catch (\Exception $exception) {
            throw new FailedException($exception->getMessage());
        }    
    }

    /**
     * 推渠道问卷
     * 
     * @param array $param
     * @return bool
     */
    public function pushQuestionnaire(array $param): bool
    {
        $userInfo = request()->user();
        $userDept = $userInfo->userDept??[];
        $department_name = $userDept['department_name']??'';

        //判断随访计划状态
        $taskInfo = (new FollowtaskModel())->getOneData(['id' => $param['task_id']], 'taskname,status');

        if ($taskInfo['status'] == 2) {
            throw new FailedException("随访计划已结束，不可进行随访");
        }

        if ($taskInfo['status'] == 3) {
            throw new FailedException("随访计划已失效，不可进行随访");
        }

        //判断全选患者
        $patientList = $param['patientList']??[];

        if (isset($param['all']) && !empty($param['all'])) {
            $patientList = (new FollowModel())->getKvData(['task_id' => new ObjectId($param['task_id']), 'follow_staff.user_id' => $userInfo['id']], 'id');

            if (empty($patientList)) {
                throw new FailedException("未查到随访患者");
            }
        }

        $pushData = [
            'projectId' => $param['projectId'],
            'creator_id' => $param['creator_id'],
            'putChanel' => $param['putChanel'],
            'deleted_at' => $param['deleted_at'],
            'creator_dept_name' => $department_name,
            'patientList' => $patientList,
            'mode'     => $param['mode'],//通过推送方式，回填历史记录/更新推送状态
            'tubeName' => 'SendFollow',
            'username' => $userInfo['username'],
            'user_id' => $userInfo['id'],
            'department_name' => $department_name,
            'department_id' => $userInfo['department_id'],
            'doctor_code' => $userInfo['doctor_code'],
        ];

        //计算延迟队列 时间
        $delay = 0;
        if (isset($param['pushtime']) && !empty($param['pushtime'])) {
            $delay = delayTime($param['pushtime']);
        }

        //推送问卷
        ZhyxBeanstalkd::getInstance()->beansTalk->useTube("sendFollow")->put(json_encode($pushData, JSON_THROW_ON_ERROR), 0, $delay);

        //推短信
//         if ($param['mode'] == 2)
//         {
//             $this->pushSms($param['task_id'], $param['template_id'], $project['id'], $patientIds, $delay, $param['mode']);
//         }
        //推微信
//        if ($param['mode'] == 1) {
//
//            $wx = [
//                'type' => 1,
//                'patientIds' => $patientIds,
//                'patient_id' => '1242651',
//                'deptName' => $userDept['department_name']??'吉林省肿瘤医院',
//                'pushtime' => date('Y-m-d'),
//                'taskname' => $taskInfo['taskname'],
//                'tubeName' => 'SendWxPush'
//            ];
//            ZhyxBeanstalkd::getInstance()->beansTalk->useTube("sendWxPush")->put(json_encode($wx, JSON_THROW_ON_ERROR), 0, $delay);
//        }
        return  true;    
    }

    /**
     * 推患者端渠道问卷
     * 
     * @param array $param
     */
    public function pushHzdQuestionnaire(array $param)
    {
        $field = 'sex,inage,name,presentTelphone';
        $info = (new PatientInfoModel())->getOneData(['patientId' => $param['patientList']], $field);

        $questData['projectId']  = $param['projectId'];
        $questData['putChanel']  = $param['putChanel'];
        $questData['deleted_at'] = 0;
        $questData['creator_id'] = 1;

        $data['sex']        = $info['sex'];
        $data['age']        = $info['inage'];
        $data['name']       = $info['name'];
        $data['mobile']     = $info['presentTelphone'];
        $data['patient_id'] = $param['patientList'];
        $data['follow_id']  = 0;
        $questData['patientList'][0] = $data;
        return (new Answer)->initQuestion($questData);
    }

    /**
     * 随访计划详情统计
     * 
     * @param string $task_id 随访计划id
     * @return array
     */
    public function getTaskAggregation(string $task_id): array
    {
        $user = request()->user();
  
        $taskret = (new FollowtaskModel())->getOneData(['id' => $task_id], 'taskname,endtime,patient_num,follow_staff');
        
        $roles = (new UsersModel())->currentUserRoleInfo($user['id'], 'role.identify')->column('identify');
  
        if (!empty(array_intersect($roles, ['dsjzxsfry'])))
        {
            $follow_staff = $user['username'];
            $patient_num = (new FollowModel())->getConditionCount(['task_id' => new ObjectId($task_id), 'follow_staff.user_id' => $user['id']]);
            $incompleteWhere[] = ['follow_staff.user_id', '=', $user['id']];
            $completedWhere[]  = ['follow_staff.user_id', '=', $user['id']];
            $diePatientWhere[] = ['follow_staff.user_id', '=', $user['id']];
        }else{
            //拼接多个随访员
            $staff  = array_column($taskret['follow_staff'], 'username');
            $follow_staff = implode(',', $staff);
            $patient_num = $taskret['patient_num'];
        }
        
        $data['head'] = [
            'taskname'     => $taskret['taskname'],
            'follow_staff' => $follow_staff,
            'endtime'      => $taskret['endtime'],
            'patient_num'  => $patient_num
        ];

        //已完成
        $completedWhere[] = ['task_id', '=', new ObjectId($task_id)];
        $completedWhere[] = ['followStatus', '=', 1];
        $completed = (new FollowModel())->getConditionCount($completedWhere);

        //未完成
        $incompleteWhere[] = ['task_id', '=', new ObjectId($task_id)];
        $incompleteWhere[] = ['followStatus', '=', 0];
        $incomplete = (new FollowModel())->getConditionCount($incompleteWhere);

        //死亡
        $diePatientWhere[] = ['task_id', '=', new ObjectId($task_id)];
        $patientIds = (new FollowModel())->where($diePatientWhere)->column('patientId');
        $dieWhere[] = ['patientId', 'in', $patientIds];
        $dieWhere[] = ['liveStatus', '=', '0'];
        $die = (new PatientInfoModel)->getNoSearchCount($dieWhere);

        $data['statistics'] = [
            'completed' => $completed,
            'incomplete' => $incomplete,
            'die' => $die
        ];
        return $data;
    }

    /**
     * 删除随访计划
     * 
     * @param string $task_id 随访id
     * @return bool
     */
    public function delTask(string $task_id): bool
    {
        try{
            $taskStatus = (new FollowtaskModel())->getOneData(['id' => new ObjectId($task_id)], 'status');

            if (empty($taskStatus))
            {
                throw new FailedException("没有此任务");
            }

            if ($taskStatus['status'] <> 0)
            {
                throw new FailedException("只有未开始的任务可以删除");
            }

            $follow = (new FollowModel())->getConditionData(['task_id' => new ObjectId($task_id)], 'id,pid');

            $task = (new FollowtaskModel())->delData($task_id);

            if ($task)
            {
                $followIds = [];
                $patientPids = [];
                foreach ($follow as $key => $val)
                {
                    $followIds[] = $val['id'];
                    $patientPids[] = new ObjectId($val['pid']);
                }
                (new FollowModel())->del($followIds);
                (new PatientInfo())->whereIn('id', $patientPids)->update(['establish_followtask_node' => '']);
            }
            return  $task;
        } catch (\Exception $exception) {
            throw new FailedException($exception->getMessage());
        }
    }

    /**
     * 获取可编辑的随访计划任务信息
     * 
     * @param string $task_id
     * @return array
     */
    public function editTask(string $task_id): array
    {
        $field = "id,taskname,patient_num,endtime,follow_staff,template_id,sms_id";
        $task = (new FollowtaskModel())->getOneData(['id' => new ObjectId($task_id), 'status' => 0], $field);

        if (empty($task))
        {
            throw new FailedException("当前任务不可编辑");
        }

        $follows = (new FollowModel())->getConditionData(['task_id' => new ObjectId($task_id)], 'pid');
        $task['patientList'] = $follows;
        return $task->toArray();
    }

    /**
     * 发送短信
     *
     * @param string $task_id 随访计划id
     * @param integer $template_id 短信模板id
     * @param string $project_id 问卷主键
     * @param array $patientIds 患者（多个）
     * @param integer $delay 队列延迟时间
     * @param integer $mode 推随访类型 1微信，2短信，3微信/短信
     * @return bool
     */
    private function pushSms(string $task_id, int $template_id, string $project_id, array $patientIds, int $delay, int $mode): bool
    {
        $userInfo = request()->user();
        $sendDeptInfo = (new Department())->findBy($userInfo["department_id"]);
        $tubeData["source"] = "随访问卷";
        $tubeData["task_id"] = $task_id;
        $tubeData["template_id"] = $template_id??"";
        $tubeData["business_id"] = $project_id;
        $tubeData["users"] = $patientIds;
        $tubeData['tubeName'] = 'SendSms';
        $tubeData["userInfo"] = [
            "id" => $userInfo["id"],
            "username" => $userInfo["username"],
            "doctor_code" => $userInfo["doctor_code"],
            "dept_name" => $sendDeptInfo["department_name"] ?? "",
        ];

        switch ($mode) {
            case 1:
                $channel = 'APP';
                break;
            case 2:
                $channel = 'SMS';
                break;
            case 3:
                $channel = 'ALL';
                break;
            default:
                throw new FileException("推送类型错误");
        }
        \app\common\lib\PushMessage::getInstance()->send($tubeData, $channel, $delay);
        return  true;
    }

    /**
     * 获取来电信息
     * @param string $id
     * @param string $mobile
     * @return array
     */
    public function getIncomingTel(string $id='', string $mobile=''): array
    {
        if (!empty($id)) {
            $where[] =['_id', '=', $id];
        } elseif(!empty($mobile)) {
            $where[] = ['relationInfo.mobile', '=', $mobile];
        }else{
            throw new FailedException("参数不能为空");
        }

        $info = (new PatientInfoModel())->getOneData($where, 'id,patientId,name,bz,medicalRecordsNo,presentTelphone,staging_status');

        if (!isset($info) || empty($info))
        {
            throw new FailedException("暂无联系方式");
        }

        $follow = (new FollowModel())->getOneData(['patientId' => $info['patientId']]);

        $followStatusDic = ['未完成' => 0, '已完成' => 1];

        $list['follow_id'] = '';
        $list['task_id'] = '';
        $list['taskname'] = '';
        if ($follow) {
            $list['follow_id'] = $follow['id'];
            $list['task_id'] = (string)$follow['task_id'];
            $list['taskname'] = $follow['taskname'];
        }
        $list['id']               = $info['id'];
        $list['name']             = $info['name'];
        $list['patientId']        = $info['patientId'];
        $list['medicalRecordsNo'] = $follow['medicalRecordsNo']??'';
        $list['presentTelphone']  = !empty($mobile)?$mobile:$info['presentTelphone'];
        $list['diagnose']         = $follow['diagnosis']??'';
        $list['inhospitalNo']     = $follow['inhospitalNo']??'';
        $list['birthdate']        = $follow['birthdate']??'';
        $list['inchargeDoctorName'] = $follow['inchargeDoctorName']??'';
        $list['dutyNurseName']      = $follow['dutyNurseName']??'';
        $list['outhospitalDate']    = $follow['outhospitalDate'];
        $list['staging_status']     = $info['staging_status'] ?? '';
        $list['followStatus']       = $followStatusDic[$follow['followStatus']];
        $list['time_of_birth']      = $follow['time_of_birth'];


        //计算年龄
        if (!empty($follow['birthdate'])) {
            $list['inage'] = floor((time() - strtotime($follow['birthdate'])) / 31556926); // 计算年龄
        }
        return $list;
    }

    /**
     * 获取部门随访统计
     *
     * @return array
     */
    public function getFollowDepartmentReport()
    {
        $report = (new FollowModel())->getFollowDepartmentList();

        if(!empty($report))
        {
            $totalArr = clone $report[0];
            $totalArr["department_name"]="合计";
            $keys = array_keys((array)$totalArr);
            for($i=1;$i<count($report);$i++){
                foreach($keys as $k){
                    if(isset($report[$i][$k])){
                        if(is_string($report[$i][$k])){
                            continue;
                        }else if(is_object($report[$i][$k])){
                            foreach($report[$i][$k] as $ck=>$cv){
                                $totalArr[$k]->$ck +=$cv;
                            }
                        }else{
                            $totalArr[$k] += $report[$i][$k];
                        }
                    }
                }
            }
            $report[] = $totalArr;
        }
        return $report;
    }

    /**
     * 处理筛选条件
     *
     * @param array $condition 筛选条件
     * @return array
     */
    private function processFilter(array $condition=[]): array
    {
        $titles = [
            "medicalRecordsNo" => '病案号',
            "startage" => '入院年龄起',
            "endage" => '入院年龄止',
            "sex" => '性别',
            "diagnosis" => '疾病诊断名称',
            "diseaseNo" => '住院疾病诊断编码',
            "mz_diseaseNo" => '门诊疾病诊断编码',
            "diseaseType" => '病种编码',
            "diseaseTypeName" => '病种',
            "mzDate" => '门诊时间',
            "inDate" => '入院时间',
            "inDeptWard" => '入院科室/病区',
            "outDate" => '出院时间',
            "outDeptWard" => '出院科室/病区',
            "ratio" => '抽取比例',
            "cycle" => '随访周期'
        ];

        $sex = [1 => '男', 2 => '女'];

        $rets = [];
        foreach ($condition as $k => $v)
        {
            if (is_array($v)){
                $v = array_filter($v);
            }
            if (!empty($v))
            {
                $ret =[];
                if(array_key_exists($k,$titles)) {
                    $ret['title'] = $titles[$k];
                    $ret['originalField'] = $k;

                    if ($k == "diseaseType") {
                        continue;
                    }

                    if ($k == "sex") {
                        $ret['val'] = $sex[(int)$v];
                    } elseif ($k == "inDate" || $k == "outDate" || $k == "mzDate") {
                        if (!empty($v)) {
                            $ret['val'] = $v[0];

                            if (count($v) > 1) {
                                $ret['val'] .= "至" . $v[1];
                            }
                        }
                    } elseif ($k == "ratio") {
                        $ret['val'] = $v . '%';
                    } elseif ($k == "diseaseTypeName") {
                        $ret['val'] = implode(',', $v)??[];
                    } else{
                        $ret['val'] = $v;
                    }
                    $rets[] = $ret;

                }
            }  
        }
        return $rets;
    }

    /**
     * 随访路径-自动推送随访问卷
     * @param string $patientId 患者id
     * @param string $projectId 问卷模板id
     * @param int $template_id 短信模板id
     * @param int $mode 推送类型 1微信，2短信，3微信&短信
     * @return array
     */
    public function automaticPushFollow(string $patientId, string $projectId, int $template_id, int $mode=1): array
    {
        //获取患者信息
        $patientField = 'id,name,timeLine,sex,inage,presentTelphone';
        $patientWhere[] = ['patientId', '=', $patientId];
        $patientInfo = (new PatientInfoModel())->getOneData($patientWhere, $patientField);
        if (empty($patientInfo)) {
            throw new FileException("未查询到患者");
        }

        //获取问卷名称
        $project = (new ProjectModel())->where('projectId', $projectId)->field('id,name,parentId')->find();

        //follow_history表主键
        $history_id = new ObjectId();

        $questData['projectId']  = $projectId;
        $questData['creator_id'] = 0;
        $questData['putChanel']  = "sms";
        $questData['deleted_at'] = 0;

        //推送问卷
        $questData['patientList'][] = [
            'follow_id'  => 0,
            'history_id' => (string)$history_id,
            'sex'        => $patientInfo['sex'],
            'age'        => $patientInfo['inage'],
            'name'       => $patientInfo['name'],
            'mobile'     => $patientInfo['presentTelphone'],
            'patient_id' => $patientId,
            'task_id'    => '',
            'is_auto'    => 1
        ];

        //随访记录
        $historyData = [
            '_id'               => $history_id,
            'mode'              => $mode,
            'projectId'         => $projectId,
            'projectName'       => $project['name'],
            'patientId'         => $patientId,
            'pid'               => $patientInfo['id'],
            'diagnosis'         => $patientInfo['timeLine'][0]['diagnosis']??'',
            'status'            => 0,
            'deleted_at'        => 0,
            'resultIsEffective' => 1,
            'pushtime'          => date('Y-m-d'),
            'pushdatetime'      => date('Y-m-d H:i:s'),
            'created_at'        => time(),
            'updated_at'        => time(),
            'year_month'        => (int)date("Ym"),
            'year'              => (int)date("Y"),
        ];

        //推送消息
        $messageData = [
            'type'        => 1,
            'typeName'    => '随访',
            'pushtime'    => date('Y-m-d'),
            'pushdatetime'=> date('Y-m-d H:i:s'),
            'patientId'   => $patientId,
            'projectId'   => $projectId,
            'projectName' => $project['name'],
            'content'     => '您好'.$patientInfo['name'].',为您推送'.$project['name'].'随访内容',
            'deleted_at'  => 0,
            'created_at'  => time(),
            'history_id'  => (string)$history_id,
            'isview'      => 0,
            'category'    => 'Patient'
        ];

        try{
            (new PushMessageModel())->save($messageData);
            (new FHModel())->save($historyData);
            $answer = (new Answer())->initQuestion($questData);
            if (!$answer){
                throw new FailedException('推送问卷错误');
            }
            return [
                'history_id' => (string)$history_id
            ];

            //推短信
            // if ($param['mode'] == 2)
            // {
            //     $this->pushSms($template_id, $projectId, [$patientId], 0);
            // }

        } catch (\Exception $exception) {
            throw new FailedException($exception->getMessage());
        }
    }


    /**
     * 随访路径-保存电话结果
     * @param array $req 参数
     * @return array
     */
    public function automaticTelResult(array $req): array
    {
        $user = request()->user();
        $userDept = $userInfo->userDept ?? [];

        $patientInfo = (new PatientInfoModel())->getOneData([['patientId', '=' ,$req['patientId']]], 'id,inList');

        if (empty($patientInfo)) {
            throw new FailedException('未查到患者信息');
        }

        //结果参数
        $history_id = new ObjectId();

        $resultData = [
            '_id'                 => $history_id,
            'mode'                => 4,
            'staffId'             => $user['id'],
            'staffName'           => $user['username'],
            'staffDepartment'     => $user['department_id'],
            'staffDoctorCode'     => $user['doctor_code'],
            'staffDepartmentName' => $userDept['department_name']??'',
            'year'                => (int)date("Y"),
            'year_month'          => (int)date("Ym"),
            'pid'                 => $patientInfo['id'],
            'patientId'           => $req['patientId'],
            'pushtime'            => date("Y-m-d"),
            'pushdatetime'        => date("Y-m-d H:i:s"),
            'created_at'          => time(),
            'updated_at'          => time(),
            'deleted_at'          => 0,
            'status'              => 2,
            'duration'            => isset($param['duration'])&&!empty($param['duration'])?(int)$param['duration']:'',//通话时长
            'diagnosis'           => $patientInfo['inList']['diagnose']??'',
            'callingNumber'       => $req['callingNumber'],
            'contactNumber'       => $req['contactNumber'],
            'contactName'         => $req['contactName'],
            'relation'            => $req['relation'],
            'relationName'        => $req['relationName'],
            'remarks'             => $req['remarks']??'',
            'result'              => $req['result'],
            'resultCategory'      => $req['resultCategory'],
            'resultName'          => $req['resultName'],
            'resultIsEffective'   => $req['is_effective'],
            'audio'               => $req['audio']??'',
            'health_status'       => $req['health_status']??'',//身体状况
            'adverse_reaction'    => $req['adverse_reaction']??'',//不良反应
            'followup_conclusion' => $req['followup_conclusion']??'',//随访结论
            'is_temporary'        => isset($req['is_temporary'])&&$req['is_temporary']==1?1:0
        ];

        //按随访结果追加参数
        switch ($req['result']) {
            case 6://复发
                $resultData['recurrence'] = $req['recurrence']??[];
                break;
            case 19://死亡
                $resultData['death'] = $req['death']??[];
                break;
            case 27://转移
                $resultData['transfer'] = $req['transfer']??[];
                break;
            default:
                break;
        }

        //是否有效参数
        $validData = [
            'sid'      => $req['sid'],
            'is_valid' => $req['is_valid']
        ];

        $ret = $this->saveTelFollowResult([], $resultData, $validData);

        if ($ret === true) {
            (new DiseasePatientTaskDetail())->modifyStatus($req['path_id'],2, $history_id);

            return [
                'history_id' => $history_id
            ];
        }

        throw new FileException('保存电话结果失败');
    }

    /**
     * 保存电话随访结果
     * @param array $param 参数
     * @param $user
     * @param $userDept
     * @return bool
     */
    public function savePhoneFollowResults(array $param, $user, $userDept): bool
    {
        //判断随访计划状态
        $taskInfo = (new FollowtaskModel())->getOneData(['id' => new ObjectId($param['task_id'])], 'status');

        $errorMessage = ($taskInfo['status'] == 2) ? "随访计划已结束，不可进行随访" : (($taskInfo['status'] == 3) ? "随访计划已失效，不可进行随访" : null);

        if ($errorMessage !== null) {
            throw new FailedException($errorMessage);
        }

        //获取随访信息
        $followInfo = (new FollowModel())->getOneData(['id' => $param['follow_id']], 'pid,patientId,name,taskname,diagnosis');

        //随访参数
        $followData = [
            'mode'         => 4,
            'follow_id'    => $param['follow_id'],
            'pushStaff'    => $user['id'],
            'followStatus' => 1,
            'is_effective' => $param['is_effective'],
            'result'         => $param['result'],
            'resultCategory' => $param['resultCategory'],
            'resultName'     => $param['resultName'],
            'pushtime'     => date("Y-m-d"),
            'pushdatetime' => date("Y-m-d H:i:s"),
        ];

        //结果参数
        $resultData = [
            'mode'                => 4,
            'staffId'             => $user['id'],
            'staffName'           => $user['username'],
            'staffDepartment'     => $user['department_id'],
            'staffDoctorCode'     => $user['doctor_code'],
            'staffDepartmentName' => $userDept['department_name']??'',
            'task_id'             => new ObjectId((string)$param['task_id']),
            'follow_id'           => new ObjectId((string)$param['follow_id']),
            'year'                => (int)date("Y"),
            'year_month'          => (int)date("Ym"),
            'patientId'           => $followInfo['patientId'],
            'pid'                 => $followInfo['pid'],
            'name'                => $followInfo['name'],
            'taskname'            => $followInfo['taskname'],
            'pushtime'            => date("Y-m-d"),
            'pushdatetime'        => date("Y-m-d H:i:s"),
            'status'              => 2,
            'duration'            => isset($param['duration'])&&!empty($param['duration'])?(int)$param['duration']:'',//通话时长
            'diagnosis'           => $followInfo['diagnosis'],
            'deleted_at'          => 0,
            'callingNumber'       => $param['callingNumber'],
            'contactNumber'       => $param['contactNumber'],
            'contactName'         => $param['contactName'],
            'relation'            => $param['relation'],
            'relationName'        => $param['relationName'],
            'remarks'             => $param['remarks']??'',
            'result'              => $param['result'],
            'resultCategory'      => $param['resultCategory'],
            'resultName'          => $param['resultName'],
            'resultIsEffective'   => $param['is_effective'],//是否有效随访
            'audio'               => $param['audio']??'',//录音
            'health_status'       => $param['health_status']??'',//身体状况
            'adverse_reaction'    => $param['adverse_reaction']??'',//不良反应
            'followup_conclusion' => $param['followup_conclusion']??'',//随访结论
            'is_temporary'        => isset($param['is_temporary'])&&$param['is_temporary']==1?1:0
        ];

        //按随访结果追加参数
        switch ($param['result']) {
            case 6://复发
                $resultData['recurrence'] = $param['recurrence']??[];
                break;
            case 19://死亡
                $resultData['death'] = $param['death']??[];
                break;
            case 27://转移
                $resultData['transfer'] = $param['transfer']??[];
                break;
            default:
                break;
        }

        //是否有效参数
        $validData = [
            'sid'      => $param['sid'],
            'is_valid' => $param['is_valid']
        ];

        return $this->saveTelFollowResult($followData, $resultData, $validData);
    }

    /**
     * 保存电话随访结果
     *
     * @param array $followData 随访数据
     * @param array $resultData 结果数据
     * @param array $validData 是否有效随访数据
     * @param int $type 1 添加， 2 修改
     * @return bool
     */
    public function saveTelFollowResult(array $followData=[], array $resultData=[], array $validData=[], int $type=1): bool
    {
        try{
            $patientData = [];
            //随访结果-死亡，患者信息表标记死亡
            if ($resultData['result'] == 19) {
                $patientData['liveStatus'] = '0';
                if (isset($resultData['death']) && !empty($resultData['death'])) {
                    $patientData['death'] = $resultData['death'];
                }
                (new CollectClassModel())->pullNode([$resultData['pid']]);
            }

            //随访结果为空号，错号，拒绝随访，标记为失访患者
            if (in_array($resultData['result'], [8, 10, 16]) && $resultData['is_temporary'] <> 1) {
                $patientData['lost_access'] = 1;
                $patientData['lost_access_result_code'] = $resultData['result'];
                $patientData['lost_access_result'] = $resultData['resultName'];
                $patientData['lost_access_date'] = date('Y-m-d');
            }

            //暂存，随访状态为暂存
            if ($resultData['is_temporary'] == 1) {
                $followData['followStatus'] = 2;
                $resultData['status'] = 3;
            }

            //1 添加， 2 修改
            if ($type == 1) {
                //标记联系人号码是否有效
                if (isset($validData['sid']) && !empty($validData['sid'])) {

                    (new PatientInfoModel())->setToData('relationInfo.sid', $validData['sid'], 'relationInfo.$.is_valid', $validData['is_valid']);
                }
                $follow_time = date("Y-m-d");

                //保存随访结果
                $resultData['created_at'] = time();
                $resultData['updated_at'] = time();
                $resultData['deleted_at'] = 0;
                $history_id = (new FHModel())->insertGetId($resultData);

                //追加随访结果到患者信息
                $pResult = [
                    'history_id'        => (string)$history_id,
                    'result'            => $resultData['result'],
                    'resultCategory'    => $resultData['resultCategory'],
                    'resultName'        => $resultData['resultName'],
                    'resultIsEffective' => $resultData['resultIsEffective'],//是否有效随访
                ];

                //追加随访时间到患者信息
                $pFollowTime = [
                    'history_id' => (string)$history_id,
                    'pushtime' => date('Y-m-d'),
                ];

                //追加随访节点到患者信息
                $this->appendFollowNode($resultData['pid'], $pResult, $pFollowTime);

            }else{
                $follow_time = $resultData['pushtime'];
                (new FHModel())->saveData($resultData['id'], $resultData);

                //检测是否为死亡患者，是否则复活
                if ($resultData['result'] <> 19) {
                    $patientLive = (new PatientInfoModel())
                        ->where('id', $resultData['pid'])
                        ->field('liveStatus')
                        ->find();
                    if ($patientLive['liveStatus'] == '0') {
                        $patientData['liveStatus'] = 1;
                        $patientData['death'] = '';
                    }
                }

                //追加随访结果节点到患者信息
                $pResult = [
                    'history_id'        => (string)$resultData['id'],
                    'result'            => $resultData['result'],
                    'resultCategory'    => $resultData['resultCategory'],
                    'resultName'        => $resultData['resultName'],
                    'resultIsEffective' => $resultData['resultIsEffective'],//是否有效随访
                ];
                $this->appendFollowNode($resultData['pid'], $pResult, [],2);
            }

            //如果是随访打电话，变更随访状态
            if (!empty($followData)) {
                (new FollowModel())->saveData($followData['follow_id'], $followData);
            }

            //更新患者最新随访记录
            $patientData['follow_node'] = [
                'follow_time' => $follow_time,
                'mode' => '电话',
                'source' => '随访计划',
                'result' => $resultData['result'],
                'resultName' => $resultData['resultName']
            ];

            $patientData['establish_followtask_node.followStatus'] = 1;

            (new PatientInfoModel())->saveData($resultData['pid'], $patientData);

            return true;
        } catch (\Exception $exception) {
            throw new FailedException($exception->getMessage());
        }
    }

    /**
     * 分娩保存电话随访结果
     * @param array $data 参数
     * @param $user
     * @param $userDept
     * @return bool
     */
    public function saveDoctorFollowResults(array $data, $user, $userDept): bool
    {
        try {
            //获取随访信息
            $followInfo = (new FollowModel())->getOneData(['id' => $data['follow_id']]);

            $projectName = '';
            //如果不是失访患者问卷必填
            if (!isset($data['lost_access']) || empty($data['lost_access']) || $data['lost_access'] <> 1) {
                if (!isset($data['projectId']) || !isset($data['answer_id'])) {
                    throw new FailedException("问卷不能为空");
                }

                //获取问卷名称
                $projectInfo = (new ProjectModel())->where('projectId', $data['projectId'])->field('name')->find();
                $projectName = $projectInfo['name'];
            }

            //获取患者信息
            #$patientInfo = (new PatientInfoModel())->where('id', new ObjectId($data['pid']))->find();

            #$objectId = new ObjectId();

            //随访详情更新参数
            $followData = [
                'mode' => 4,
                'staffId'             => $user['id'],
                'staffName'           => $user['username'],
                'staffDoctorCode'     => $user['doctor_code'],
                'staffDepartmentId'   => $user['department_id'],
                'staffDepartmentName' => $userDept['department_name']??'',
                'followStatus' => 1,
                'projectId'    => $data['projectId']??'',
                'projectName'  => $projectName??'',
                'answer_id'    => $data['answer_id']??'',
                'problem'      => $data['problem']??'',//问题
                'pushtime'     => date("Y-m-d"),
                'pushdatetime' => date("Y-m-d H:i:s"),
                'audio'        => $data['audio']??'',//录音
                'notes'        => $data['notes']??'',//备注
            ];

            //处理失访患者
            $patientData = [];
            if ((isset($data['lost_access']) && !empty($data['lost_access'])) && $data['lost_access'] === 1) {
                $patientData['lost_access'] = $data['lost_access'];
                $patientData['lost_access_date'] = date("Y-m-d");
                $patientData['lost_access_result'] = $data['lost_access_result']??'';
                $patientData['lost_access_operator_id'] = $user['id']??'';
                $patientData['lost_access_operator_name'] = $user['name']??'';
                $patientData['lost_access_operator_doctor_code'] = $user['doctor_code']??'';
                $patientData['lost_access_operator_department_id'] = $user['department_id']??'';
                $patientData['lost_access_operator_department_name'] = $userDept['department_name']??'';
            }

            //随访记录更新参数
            $historyData = [
                'mode'                => 4,
                'staffId'             => $user['id'],
                'staffName'           => $user['username'],
                'staffDoctorCode'     => $user['doctor_code'],
                'staffDepartmentId'   => $user['department_id'],
                'staffDepartmentName' => $userDept['department_name']??'',
                'follow_id'           => new ObjectId($data['follow_id']),
                'pid'                 => $followInfo['pid'],
                'patientId'           => $followInfo['patientId'],
                'name'                => $followInfo['name'],
                'year'                => (int)date("Y"),
                'year_month'          => (int)date("Ym"),
                'pushtime'            => date("Y-m-d"),
                'pushdatetime'        => date("Y-m-d H:i:s"),
                'diagnosis'           => $followInfo['diagnosis'],
                'callingNumber'       => $data['callingNumber'],
                'contactNumber'       => $data['contactNumber'],
                'contactName'         => $data['contactName'],
                'relation'            => $data['relation'],
                'relationName'        => $data['relationName'],
                'audio'               => $data['audio']??'',//录音
                'problem'             => $data['problem']??'',//问题
                'projectId'           => $data['projectId']??'',
                'projectName'         => $projectName??'',
                'answer_id'           => $data['answer_id']??'',
                'status'              => 2,
                'deleted_at'          => 0,
                'duration'            => $data['duration']??'',//通话时长
                'lost_access'         => $patientData['lost_access']??'',
                'notes'               => $data['notes']??'',//备注
            ];

            (new FollowModel())->saveData($data['follow_id'], $followData);
            (new FHModel())->insertGetId($historyData);

            $followReportData = [
                'pid'                 => $followInfo['pid'],
                'patientId'           => $followInfo['patientId'],
                'name'                => $followInfo['name'],
                'follow_id'           => new ObjectId($data['follow_id']),
                'staffId'             => $user['id'],
                'staffName'           => $user['username'],
                'staffDoctorCode'     => $user['doctor_code'],
                'staffDepartmentId'   => $user['department_id'],
                'staffDepartmentName' => $userDept['department_name']??'',
                'outhospitalDept'     => $followInfo['outhospitalDept']??'',
                'outhospitalDeptCode' => $followInfo['outhospitalDeptCode']??'',
                'pushtime'            => date("Y-m-d"),
                'pushdatetime'        => date("Y-m-d H:i:s"),
                'followStatus'        => 1,
                'deleted_at'          => 0,
                'duration'            => $data['duration']??'',//通话时长
                'lost_access'         => $patientData['lost_access']??'',
            ];

            (new FollowDeliverReport())->where('follow_id', new ObjectId($data['follow_id']))->update($followReportData);
            //更新联系方式是否有效状态
            if (isset($data['sid'], $data['is_valid']) && !empty($data['sid']) && !empty($data['is_valid'])) {
                (new PatientInfoModel())->setToData('relationInfo.sid', $data['sid'], 'relationInfo.$.is_valid', $data['is_valid']);
            }

            $patientData['levelNode.new'] = [
                'projectId'           => $data['projectId']??'',
                'answer_id'           => $data['answer_id']??'',
                'projectName'         => $projectName??'',
                'staffId'             => $user['id'],
                'staffName'           => $user['username'],
                'staffDoctorCode'     => $user['doctor_code'],
                'staffDepartmentId'   => $user['department_id'],
                'staffDepartmentName' => $userDept['department_name']??'',
                'audio'               => $data['audio']??'',//录音
                'problem'             => $data['problem']??'',//问题
                'follow_id'           => new ObjectId($data['follow_id']),
                'pushtime'            => date("Y-m-d"),
                'pushdatetime'        => date("Y-m-d H:i:s"),
                'notes'               => $data['notes']??''//备注
            ];

            //更新患者随访节点
            if (!empty($patientData)) {
                (new PatientInfoModel())->saveData($followInfo['pid'], $patientData);
            }

            //更新患者随访级别次数
            $patientLevelNode = [
                '$inc' => [
                    'levelNode.followNum' => 1
                ]
            ];
            ZhyxMongo::getInstance()->setCollection("patient_info")->updateOne([
                '_id' => new ObjectId($followInfo['pid'])
            ], $patientLevelNode);

            $key = "projectAndAnswer:".$data['projectId'].":".$followInfo['patientId'];
            Redis::getInstance()->redis->del($key);

            return true;
        } catch (\Exception $exception) {
            throw new FailedException($exception->getMessage());
        }
    }

    /**
     * 电话随访切换下一位患者
     */
    public function switchToNextPosition($task_id, $userId, $type, $id)
    {
        $where[] = ['task_id', '=', new ObjectId($task_id)];
        #$where[] = ['follow_staff.user_id', '=', $userId];
        $where[] = ['followStatus', '=', 0];

        //type=1 为上一位
        if ($type == 1) {
            $where[] = ['id', '>', $id];
            $sort = 'asc';
        }else{
            $where[] = ['id', '<', $id];
            $sort = 'desc';
        }
        $ret = (new FollowModel())
                ->where($where)
                ->field('id,pid,patientId')
                ->order('_id', $sort)
                ->find();
        if (!$ret) {
            throw new FailedException("暂无患者");
        }
        return $ret;
    }

    /**
     * 修改随访结果
     */
    public function modifyFollowResult($param)
    {
        $userInfo = request()->user();

        $followData = [];
        if ($param['follow_id']) {
            $followData = [
                'follow_id'    => $param['follow_id']['$oid'],
                'is_effective' => $param['is_effective'],
                'result'         => $param['result'],
                'resultCategory' => $param['resultCategory'],
                'resultName'     => $param['resultName'],
                'modifytime'     => date("Y-m-d"),
                'modifydatetime' => date("Y-m-d H:i:s"),
            ];
        }

        $resultData = [
            'id'                  => $param['id'],
            'pid'                 => $param['pid'],
            'remarks'             => $param['remarks'],
            'result'              => $param['result'],
            'resultCategory'      => $param['resultCategory'],
            'resultName'          => $param['resultName'],
            'resultIsEffective'   => $param['is_effective'],//是否有效随访
            'health_status'       => $param['health_status'],//身体状况
            'adverse_reaction'    => $param['adverse_reaction'],//不良反应
            'followup_conclusion' => $param['followup_conclusion'],//随访结论
            'pushtime'            => $param['pushtime'],
            'pushdatetime'        => $param['pushdatetime'],
            'modify_user_id'      => $userInfo['id'],
            'modify_user_name'    => $userInfo['username'],
            'modifytime'          => date("Y-m-d"),
            'modifydatetime'      => date("Y-m-d H:i:s"),
            'is_temporary'        => 0
        ];

        //按随访结果追加参数
        switch ($param['result']) {
            case 6://复发
                $resultData['recurrence'] = $param['recurrence']??[];
                break;
            case 19://死亡
                $resultData['death'] = $param['death']??[];
                break;
            case 27://转移
                $resultData['transfer'] = $param['transfer']??[];
                break;
            default:
                break;
        }

        $this->saveTelFollowResult($followData, $resultData, [], 2);
        return true;
    }

    /**
     * 追加随访节点到患者信息
     * @param string $pid
     * @param array $result
     * @param array $followTime
     * @param int $type 1 添加，2 修改
     * @return bool
     */
    public function appendFollowNode(string $pid, array $result=[] ,array $followTime=[], int $type=1): bool
    {
        try {
            if ($type == 1) {
                $user = request()->user();
                $userDept = $userInfo->userDept ?? [];

                //随访人员
                $is_staff = (new PatientInfoModel())->where([
                    ['id', '=', $pid],
                    ['follow_history.follow_staff.user_id', '=', $user['id']]
                ])->findOrEmpty()->toArray();

                if (!$is_staff) {

                    $userInfo = [
                        'user_id' => $user['id'],
                        'username' => $user['username'],
                        'department_id' => $user['department_id'] ?? '',
                        'doctor_code' => $user['doctor_code'],
                        'department_name' => $userDept['department_name'] ?? ''
                    ];

                    ZhyxMongo::getInstance()->setCollection("patient_info")->updateOne(['_id' => new ObjectId($pid)], ['$push' => ['follow_history.follow_staff' => $userInfo]]);
                }

                //随访结果
                $is_result = (new PatientInfoModel())->where([
                    ['id', '=', $pid],
                    ['follow_history.follow_result.result', '=', $result['result']]
                ])->findOrEmpty()->toArray();

                if (!$is_result) {
                    ZhyxMongo::getInstance()->setCollection("patient_info")->updateOne(
                        ['_id' => new ObjectId($pid)],
                        ['$push' => ['follow_history.follow_result' => $result]]
                    );
                }

                //随访时间
                $is_follow_time = (new PatientInfoModel())->where([
                    ['id', '=', $pid],
                    ['follow_history.follow_time.history_id', '=', $followTime['history_id']]
                ])->findOrEmpty()->toArray();

                if (!$is_follow_time) {
                    ZhyxMongo::getInstance()->setCollection("patient_info")->updateOne(
                        ['_id' => new ObjectId($pid)],
                        ['$push' => ['follow_history.follow_time' => $followTime]]
                    );
                }
            }else{
                $is_result = (new PatientInfoModel())->where([
                    ['id', '=', $pid],
                    ['follow_history.follow_result.history_id', '=', $result['history_id']]
                ])->findOrEmpty()->toArray();

                if ($is_result) {
                    ZhyxMongo::getInstance()->setCollection("patient_info")->updateMany(
                        ['_id' => new ObjectId($pid), "follow_history.follow_result.history_id" => $result['history_id']],
                        ['$set' => ["follow_history.follow_result.$" => $result]]
                    );
                }
            }
        } catch (\Exception $exception) {
            \think\facade\Log::record("追加随访节点到患者信息:" . $exception->getMessage(), "error");
            throw new FailedException($exception->getMessage());
        }
        return true;
    }

    /**
     * 批量撤销失访患者
     * @param array $ids 患者主键id
     * @return bool
     */
    public function batchRevocationLost(array $ids=[]): bool
    {
        try {
            $data = [];
            foreach ($ids as $key => $val) {
                $data[] = [
                    'id' => $val,
                    'lost_access' => 0,
                    'lost_access_date' => '',
                    'lost_access_result' => '',
                    'lost_access_result_code' => '',
                    'lost_access_phone_status' => '',
                    'lost_access_visit_status' => '',
                ];
            }
            if ($data) {
                (new PatientInfoModel())->saveAll($data);
            }
            return true;
        } catch (\Exception $exception){
            throw new FailedException($exception->getMessage());
        }
    }
}